package com.atguigu.lease.common.utils;

import com.atguigu.lease.common.exception.LeaseException;
import com.atguigu.lease.common.result.ResultCodeEnum;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;

import javax.crypto.SecretKey;
import java.util.Date;

/**
 * ClassName: JwtUtil
 * Package: com.atguigu.lease.common.utils
 * Description:
 *
 * @Author: tiantian
 * @Create: 2024/10/9 - 12:07
 * @Version: v1.0
 */
public class JwtUtil {
    //专门给hmac这个签名算法构造密钥的（输入一个字符串作为密码，得到字节数组） 得到SecretKey对象（key类型的子类）
    //密码强度：必须大于等于256 位

    //用户携带Token携带请求的时候，我们需要解析Token来验证身份，解析的时候，也会用到32位的密钥
    //最好将密钥声明成静态的成员变量，解析Token的时候也可以使用
    private static SecretKey secretKey = Keys.hmacShaKeyFor("LDhpFD0dTF3Cd5KTiOflg2lrdH3jVVXq".getBytes());

    //token需要包含用户的标识（id和用户名字）设置两个参数作为标识
    public static String createToken(Long userId, String username){
        //得到构造器，通过一系列方法设置JWT的各种属性

        //第一部分：header不需要考虑

        //重点关注：负载：第二部分，签名：第三部分

        //claim：来声明自己定义的字段（官方定义的字段 + 用户自定义的字段）
        //setExpiration：设置过期时间（很关键）接收的是data类型的参数，
        String jwt = Jwts.builder().
                //第二部分
                //setExpiration：设置过期时间（很关键）接收的是data类型的参数
                //获取当前系统时间的时间戳，在此基础上增加了时长，九计算出来过期时间的时间点的时间戳（毫秒），根据时间戳创建了date对象
                //3600000：60分钟
                        setExpiration(new Date(System.currentTimeMillis() + 3600000*24*365L)).
                //主题：填不填都可以
                        setSubject("LOGIN_USER").
                //添加自己的字段
                        claim("userId", userId).
                claim("username", username).
                //第三部分：签名算法（SignatureAlgorithm.HS256[HS算法 长度为256位]）
                        signWith(secretKey, SignatureAlgorithm.HS256).
                compact();
        return jwt;
    }

    public static Claims parseToken(String token){
        if (token == null){
            //直接抛异常（未登录）
            throw new LeaseException(ResultCodeEnum.ADMIN_LOGIN_AUTH);
        }
        //下面的代码如果抛异常就是不合法的，不报异常就是合法的
        try {
            JwtParser jwtParser = Jwts.parserBuilder().setSigningKey(secretKey).build();
            //Claims：相当于jwt的第二部分（负载）（暂时不需要返回值）
            Jws<Claims> claimsJws = jwtParser.parseClaimsJws(token);
            return claimsJws.getBody();
        }catch (ExpiredJwtException e){
            //Token已过期
            throw new LeaseException(ResultCodeEnum.TOKEN_EXPIRED);
        }catch (JwtException e){
            //Token非法
            throw new LeaseException(ResultCodeEnum.TOKEN_INVALID);
        }

    }

    public static void main(String[] args) {
        System.out.println(JwtUtil.createToken(1L, "13888888888"));
    }
}
